﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using devtm.Helpers;
using devtm.Collections;
using System.Diagnostics;
using System.ComponentModel;
using devtm.Exceptions;
using System.Windows.Forms;

namespace devtm.Types.LazyLoading
{

    [DebuggerDisplay("Assembly = {Name}")]
    public class AssemblyNamespace : TableCollection<Type, Type>, INotifyPropertyChanged
    {


        public AssemblyNamespace()
            : base()
        {
            Resolver = new ResolveAssembly();
            References = new TableCollection<AssemblyDescription, string>(a => a._toString);
        }

        public virtual void Initialize()
        {

        }


        public virtual void Initialize(Assembly ass)
        {

            try
            {
                Assembly = ass;

                if (ass != null && AssemblyLoadEventHandler != null)
                    AssemblyLoadEventHandler(this, new AssemblyLoadEventArgs(ass));

                this.Dirs = LazyLoadingHelper.Directories;
                this.Initialized = true;
                this.Version = ass.ImageRuntimeVersion;
                Name = new AssemblyDescription(ass.FullName).ToSmallString();
                PropertyChange("Name");
            }
            catch (Exception ex)
            {

                IsInError = true;
                if (ex.Message.StartsWith("Mixed mode assembly is built against version"))
                {
                    MessageBox.Show(
                        ex.Message,
                        "Error",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Warning);

                    return;
                }
            }

        }


        public void LoadTypes()
        {

            if (!Initialized || IsInError)
                return;

            if (this.Loaded)
                return;

            Assembly ass;
            ListException listeErreur = new ListException();
            List<String> lst;

            // on Check que les dependances sont la.
            try
            {

                ass = Assembly ?? (Assembly = LoadAssembly(Filename));
                using (ResolveWorker i = new ResolveWorker(this.Resolver))
                    lst = ass.CheckReferences().ToList();

            }
            catch (Exception)
            {
                IsInError = true;
                return;
            }
            

            if (lst.Count() != 0)
            {

                foreach (string item in lst)
                    listeErreur.Add(new System.IO.FileNotFoundException("this files are not found :", item));

                throw listeErreur;
            }

            else
            {

                Type[] arr = null;


                try
                {
                    using (ResolveWorker j = new ResolveWorker(this.Resolver))
                        arr = ass.GetTypes();
                }
                catch (ReflectionTypeLoadException ex1)
                {

                    foreach (Exception item in ex1.LoaderExceptions)
                        listeErreur.Add(item);

                    arr = ex1.Types;
                    IsInError = true;
                }
                catch (Exception ex2)
                {
                    listeErreur.Add(ex2);
                    IsInError = true;
                }

                if (arr != null)
                    for (int i = 0; i < arr.Count(); i++)
                    {
                        Type t = arr[i];
                        if (t != null && !Contains(t))
                            Add(t);
                    }

            }

            this.Loaded = true;

        }

     
        public Assembly LoadAssembly(string source)
        {

            Assembly ret = null;
            using (ResolveWorker j = new ResolveWorker(this.Resolver))
            {
                if (source.Contains(","))
                    ret = System.Reflection.Assembly.Load(source);
                else
                    ret = System.Reflection.Assembly.LoadFile(source);
            }

            if (ret != null && AssemblyLoadEventHandler != null)
                AssemblyLoadEventHandler(this, new AssemblyLoadEventArgs(ret));

            return ret;
        }


        public string Name 
        { 
            get; 
            protected set; 
        }

        public uint Crc { get; set; }
        public string SingleName { get; protected set; }
        public string Filename { get; protected set; }
        public bool IsFile { get; protected set; }
        public bool Loaded { get; protected set; }
        public IEnumerable<DirectoryInfo> Dirs { get; set; }
        //protected ClsGetTypes dirroot;
        public ResolveAssembly Resolver { get; protected set; }
        public TableCollection<AssemblyDescription, string> References;
        protected bool ReferencesLoaded = false;
        private bool _isInError;
        public bool IsInError 
        {
            get { return _isInError; }
            set
            {
                if (_isInError == value)
                    return;

                _isInError = value;

                PropertyChange("IsInError");

            }
        }

        public string Version { get; set; }
        public bool Initialized { get; protected set; }
        public bool MustLoad { get; set; }

        public event EventHandler<AssemblyLoadEventArgs> AssemblyLoadEventHandler;

        public Assembly Assembly { get; protected set; }

    }
}
